home *** CD-ROM | disk | FTP | other *** search
- /*
-
- Just Finder
-
- A System 7 application that kills all processes with faces except the Finder.
- Handy for working with Fonts or any other component where you get that blasted
- Finder alert saying "Close everything but the Finder before doing this."
-
- by Matt Deatherage, Developer Support Center
- Copyright 1993 Apple Computer, Inc. All rights reserved.
-
- MD Version 1.0 released (9/13/93)
- MD 1.0.1b1. Don't let Dave code review things if you want to ship. He reminds us
- that this is not printing, and you shouldn't dispose of AEDesc structures that
- weren't succesfully created. The comments were right; the code was wrong.
- Also tightened up a loop and removed several extraneous braces left over from
- when this was more complicated.
-
- Also trying pre-compiled headers. They're by no means necessary, but I've never
- played with them before except for the default MacHeaders.
-
- */
-
- /*------ Includes ------------------------------------------------------------------------*/
-
- #include "JustHeaders"
-
- /*------ Prototypes ----------------------------------------------------------------------*/
-
- void InstalleAEHandlers(void);
- pascal OSErr oappHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon);
- pascal OSErr odocHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon);
- pascal OSErr pdocHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon);
- pascal OSErr quitHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon);
- OSErr CheckRequiredParms(AppleEvent *theAppleEvent);
- Boolean ShouldWeKill(ProcessInfoRec* processInfo);
- void KillThemAll(void);
-
- /*------ main ----------------------------------------------------------------------------*/
-
- main()
-
- {
-
- GrafPort myPort;
-
-
- InitGraf((Ptr) &qd.thePort);
- OpenPort((GrafPtr) &myPort);
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(nil);
- InitCursor();
-
- KillThemAll();
-
-
- } /* main */
-
- /*******************************************************************************************
- *
- * According to the rules, all applications that say they're high-level event aware must
- * respond to the four required Apple events. This application has no user interface and
- * doesn't deal with documents at all, nor will it quit prematurely. However, rules is
- * rules, so we install four very minimal required event handlers. The ones with parameters
- * return an OSErr that indicates whether all the parameters were read (they weren't, if
- * there were any, so it usually returns errAEEventNotHandled).
- *
- *******************************************************************************************/
-
-
-
- /*------ InstallAEHandlers ---------------------------------------------------------------*/
-
- void InstallAEHandlers(void)
- {
-
- AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,(EventHandlerProcPtr)oappHandler,
- 0,false);
- AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,(EventHandlerProcPtr)odocHandler,
- 0,false);
- AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,(EventHandlerProcPtr)pdocHandler,
- 0,false);
- AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,(EventHandlerProcPtr)quitHandler,
- 0,false);
- }
-
- /*******************************************************************************************
- *
- * CheckRequiredParams is a common Apple event utility routine -- it returns noErr if
- * someone has retrieved all the required parameters from the Apple event passed. If there
- * are still some left, it returns errAEEventNotHandled.
- *
- * The check is simple -- look for the "missed keyword" attribute. If there isn't one,
- * everything is fine.
- *
- *******************************************************************************************/
-
- /*------ CheckRequiredParms ---------------------------------------------------------------*/
-
- OSErr CheckRequiredParms(AppleEvent *theAppleEvent)
- {
-
- OSErr myErr;
- DescType attrType;
- Size attrSize;
-
- myErr = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard,
- &attrType, 0L, 0, &attrSize);
-
- if (myErr == errAEDescNotFound)
- myErr = noErr;
-
- if (myErr == noErr)
- myErr = errAEEventNotHandled;
-
- return(myErr);
-
- }
-
- /*******************************************************************************************
- *
- * The core AE handlers don't do very much except return errors saying "I didn't do that."
- *
- *******************************************************************************************/
-
- /*------ The core AE handlers -------------------------------------------------------------*/
-
- pascal OSErr oappHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
- {
-
- return(CheckRequiredParms(theAppleEvent));
-
- }
-
- pascal OSErr odocHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
- {
-
- return(errAEEventNotHandled);
-
- }
-
- pascal OSErr pdocHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
- {
-
- return(errAEEventNotHandled);
-
- }
-
- pascal OSErr quitHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
- {
-
- return(CheckRequiredParms(theAppleEvent));
-
- }
-
- /*******************************************************************************************
- *
- * ShouldWeKill is the routine that decides if a given process, as specified by a
- * ProcessInfoRec, should be killed. We kill all foreground processes that aren't this
- * application or the Finder. The ProcessInfoRec must be fully initialized by a routine
- * very similar to GetProcessInfo or else this routine will probalby do very strange things.
- *
- *******************************************************************************************/
-
- /*------ ShouldWeKill ---------------------------------------------------------------------*/
-
- Boolean ShouldWeKill(ProcessInfoRec* processInfo)
- {
-
- OSErr myErr;
- ProcessSerialNumber thisProcess;
- Boolean twinProcesses;
-
- thisProcess.highLongOfPSN = 0;
- thisProcess.lowLongOfPSN = kCurrentProcess; // set up the PSN for this application
-
- myErr = SameProcess(&(processInfo->processNumber), &thisProcess, &twinProcesses);
- // sets up twinProcesses to contain TRUE
- // if the passed process and this one are
- // one and the same
-
- if (!(twinProcesses) && // if this isn't _this_ process and
- !(processInfo->processSignature == 'MACS' && processInfo->processType == 'FNDR') &&
- // if it's not the Finder and
- !(processInfo->processMode & modeOnlyBackground))
- // if it's not background-only then
- {
- return true; // Yup, kill it, or do other things to it here.
- } else {
- return false; // Nope, it's been spared, or do other things.
- }
-
- }
-
- /*******************************************************************************************
- *
- * From looking at published sample code such as ProcDoggie and KillEveryoneButMe (1.0.1),
- * you'd think killing a process is a relatively straight-forward thing to do.
- *
- * Think again.
- *
- * This took quite some time to figure out, thanks to obscure errors like -603 coming back
- * from the Process Manager at strange times. Here's what I learned, some of which is kind
- * of obvious and some of which isn't.
- *
- * 1. Don't call GetNextProcess on a process that you've just killed. It tends to confuse
- * things. (duh...) Instead, once we kill a process, we start over at the beginning
- * of the process list, skipping those processes we don't wish to kill. You know
- * you're done when you hit the end of the process list without killing any processes.
- *
- * 2. After killing a process, the Process Manager expects you to keep processing events.
- * Remember the three calls to EventAvail() you have to do at the beginning of most
- * real applications before you become the front process? In similar ways, the Process
- * Manager might become confused if you're firing off lots of kill events but never
- * call WaitNextEvent to get any.
- *
- * So how many times should you call WaitNextEvent? I've seen numbers from 4 to 25,
- * and they didn't necessarily work for me. Instead, we call WaitNextEvent until we
- * get a null event, the system's surefire way of indicating it's not doing anything
- * major at this time. If we get a high-level event, we call AEProcessAppleEvent to
- * follow the rules -- but we ignore other events.
- *
- * Note that this might not work for you if you're an application with windows and
- * the like, because you could get an update event. If you don't process the update
- * event, it won't go away. This application has no windows and doesn't have to
- * worry about that.
- *
- *******************************************************************************************/
-
-
- /*------ KillThemAll ----------------------------------------------------------------------*/
-
- void KillThemAll(void)
- {
-
- ProcessSerialNumber theProcess;
- ProcessInfoRec ourProcessInfo;
- OSErr myErr;
- Str31 theProcessName;
- FSSpec theProcessSpec;
- AppleEvent ourQuitEvent, ourReplyEvent;
- AEAddressDesc ourPSNDesc;
- EventRecord theEvent;
-
- // set up the ourProcessInfo record to point to space we've allocated...
-
- ourProcessInfo.processInfoLength = sizeof(ProcessInfoRec);
- ourProcessInfo.processName = (StringPtr)&theProcessName;
- ourProcessInfo.processAppSpec = &theProcessSpec;
-
- theProcess.highLongOfPSN = 0;
- theProcess.lowLongOfPSN = kNoProcess; // return the first process
-
- while (true)
- {
-
- // Call WaitNextEvent until we get a null event, meaning all is calm
-
- do {
- WaitNextEvent(everyEvent, &theEvent, 600L, 0L);
- if (theEvent.what == kHighLevelEvent)
- AEProcessAppleEvent(&theEvent);
- } while (theEvent.what != nullEvent);
-
- myErr = GetNextProcess(&theProcess);
- if (myErr == procNotFound)
- break; // if no process, we're done!
-
- myErr = GetProcessInformation(&theProcess,&ourProcessInfo);
- // Check to see if we want to kill this process
-
- if (ShouldWeKill(&ourProcessInfo))
- {
-
- // Create a process serial number descriptor for this process
-
- myErr = AECreateDesc(typeProcessSerialNumber, (Ptr)&theProcess,
- sizeof(theProcess), &ourPSNDesc);
- if (myErr == noErr)
- {
-
- // Create the 'quit' Apple event for this process. This might return error
- // -603 for desk accessories if you don't call WaitNextEvent enough times
- // like above.
-
- myErr = AECreateAppleEvent(kCoreEventClass,kAEQuitApplication, &ourPSNDesc,
- kAutoGenerateReturnID, kAnyTransactionID, &ourQuitEvent);
- if (myErr == noErr)
- {
-
- // send the event
-
- myErr = AESend(&ourQuitEvent, &ourReplyEvent, kAENoReply,
- kAENormalPriority, kNoTimeOut, 0L, 0L);
-
- if (myErr == noErr)
- {
-
- // Sadly, some applications won't respond to Apple events and do
- // what they're supposed to do until they're brought to the front,
- // so we do that, and continue our work in the background.
-
- SetFrontProcess(&theProcess);
-
- }
-
- // dispose of the event only if we succesfully created it.
-
- myErr = AEDisposeDesc(&ourQuitEvent);
- }
-
- // dispose of the descriptor only if we succesfully created it.
-
- myErr = AEDisposeDesc(&ourPSNDesc);
-
- }
-
- // Now, since we killed a process, we don't want to call GetNextProcess
- // on the one we just eliminated! (That would be bad.) So we reset our
- // process record to contain the serial number of "no process", so the
- // next call to GetProcessInfo returns the first process, and we start
- // all over again.
-
- theProcess.highLongOfPSN = 0;
- theProcess.lowLongOfPSN = kNoProcess; // return to the first process
- }
- }
- }
-
-